package otc.regate.client;

import java.util.ArrayList;

/**
 * Cette classe met a disposition des methodes de calcul de distance et.
 * d'avancement dediees aux classes clientes.
 *
 * @author Escop, Jacquet, Loiret, Marboeuf, Millet, Montferrand
 *
 */
public class Utilitaire {

/** Rayon terrestre. */
public static final double rayonTerrestre = 6378.137;
/** Balises de passage. */
public static ArrayList<Coordonnees> pointsDePassage;
/** Tableau contenant les differentes forces de vent. */
public static double[][] tableauVent;
/** Distance maximal entre la balise et le bateau. */
public static double distanceBaliseAccordee = 10;
/** Dimension de la carte. */
public static int dimensionCarte;

    /**
     * Methode d'initialisation des points de passage et du tableau des vents.
     */
    public static void initialisationCourse() {

        //Initialisation de la liste des points de passage
        pointsDePassage = new ArrayList<Coordonnees>();
        pointsDePassage.add(new Coordonnees(0, 0));
        pointsDePassage.add(new Coordonnees(30, 20));
        pointsDePassage.add(new Coordonnees(10, 80));
        pointsDePassage.add(new Coordonnees(120, 120));

        dimensionCarte = 500;

        // Tableau des vents
        tableauVent = new double[dimensionCarte][dimensionCarte];

        for(int i = 0; i < dimensionCarte; i++) {
            for(int j = 0; j < dimensionCarte; j++) {
                tableauVent[i][j] = Utilitaire.nombreAleatoire(500, 1000);
            }
        }
    }

    /**
     * Permet de calculer la distance entre deux coordonnees.
     *
     * @param coordonneesDepart coordonnees de depart
     * @param coordonneesArrivee coordonnees d'arrivee
     * @return
     */
    public static double calculDistance(final Coordonnees coordonneesDepart,
                                         final Coordonnees coordonneesArrivee) {

        // Traduction des coordonnees decimales en DMS (Degre Minute Seconde)
        // Latitude
        double degreXDepart = (int) coordonneesDepart.getLatitude();
        double degreXArrivee = (int) coordonneesArrivee.getLatitude();
        double minutesXDepart = (int) ((coordonneesDepart.getLatitude()
                - degreXDepart) * 60);
        double minutesXArrivee = (int) ((coordonneesArrivee.getLatitude()
                - degreXArrivee) * 60);
        double secondesXDepart = (int) ((((coordonneesDepart.getLatitude()
                - degreXDepart) * 60) - minutesXDepart)*60);
        double secondesXArrivee = (int) ((((coordonneesArrivee.getLatitude()
                - degreXArrivee) * 60) - minutesXArrivee)*60);
        // Longitude
        double degreYDepart = (int) coordonneesDepart.getLongitude();
        double degreYArrivee = (int) coordonneesArrivee.getLongitude();
        double minutesYDepart = (int) ((coordonneesDepart.getLongitude()
                - degreYDepart) * 60);
        double minutesYArrivee = (int) ((coordonneesArrivee.getLongitude()
                - degreYArrivee) * 60);
        double secondesYDepart = (int) ((((coordonneesDepart.getLongitude()
                - degreYDepart) * 60) - minutesYDepart)*60);
        double secondesYArrivee = (int) ((((coordonneesArrivee.getLongitude()
                - degreYArrivee) * 60) - minutesYArrivee)*60);

        // Calcul de la variation angulaire
        double variationAngulaireLatitude = degreXArrivee - degreXDepart
        + (minutesXArrivee - minutesXDepart)
        / 60 + (secondesXArrivee - secondesXDepart) / 3600;

        double variationAngulaireLongitude = degreYArrivee - degreYDepart
        + (minutesYArrivee - minutesYDepart) / 60
        + (secondesYArrivee - secondesYDepart) / 3600;

        // Calcul de la variation en distance
        double variationEnDistanceLatitude = variationAngulaireLatitude
        * rayonTerrestre * (Math.PI / 180);
        double variationEnDistanceLongitude = variationAngulaireLongitude
        * rayonTerrestre * Math.cos(variationAngulaireLatitude)
        * (Math.PI / 180);

        // Calcul de la distance
        double distance =  Math.sqrt(variationEnDistanceLatitude
                * variationEnDistanceLatitude
                + variationEnDistanceLongitude
                * variationEnDistanceLongitude);
        return distance;
    }

    /**
     * Calcule une nouvelle coordonnee en fonction de la derniere coordonnee.
     * de la coordonnee de destination et de la force de vent courante.
     *
     * @param actuelle Coordonnees actuelles
     * @param destination Coordonnees de destination
     * @param forceVents force des vents
     * @return
     */
    public static Coordonnees avancement(final Coordonnees actuelle,
            final Coordonnees destination, final double forceVents) {

        // Calcul de la distance parcourue en fonction de la force des vents
        double distanceParcourue
        = nombreAleatoire(forceVents, forceVents * 1.5);

        // Si la distance depasse un point de passage,
        //la prochaine coordonnees sera ce point
        if(distanceParcourue > calculDistance(actuelle, destination)) {
            return new Coordonnees(destination.getLongitude(),
                    destination.getLatitude());

        } else {

            double pourcentage = distanceParcourue
            / calculDistance(actuelle, destination);
            double signe = -1;
            if(actuelle.getLatitude() < destination.getLatitude()) {
                signe = 1;
            }
            double lat2 = actuelle.getLatitude() + (signe
                    * (Math.abs(actuelle.getLatitude()
                            - destination.getLatitude()) * pourcentage));

            signe = -1;
            if(actuelle.getLongitude() < destination.getLongitude()) {
                signe = 1;
            }
            double lon2 = actuelle.getLongitude() + (signe
                    * (Math.abs(actuelle.getLongitude()
                            - destination.getLongitude()) * pourcentage));

            return new Coordonnees(lon2, lat2);
        }
    }

    /**
     * Retourne un nombre aleatoire.
     *
     * @param min borne min
     * @param max borne max
     * @return
     */
    public final static double nombreAleatoire(final double min,
            final double max) {       
        return ((Math.random() * (max - min)) + min);
    }
    
}
